package com.qms.qep.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;

/**
 * Word模板处理工具类
 * 
 * @author qms
 *
 */
public class WordTemplateUtil {
    
    /**
     * 使用XDocReport引擎替换Word文档中的变量标记（${variable}格式）
     * 
     * @param templatePath Word模板文件路径
     * @param outputPath 输出文件路径
     * @param dataMap 变量数据Map
     * @throws Exception 处理异常
     */
    public static void processTemplateWithXDocReport(String templatePath, String outputPath, Map<String, Object> dataMap) throws Exception {
        try (InputStream inputStream = new FileInputStream(new File(templatePath))) {
            // 加载模板
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(inputStream, TemplateEngineKind.Freemarker);
            
            // 创建上下文
            IContext context = report.createContext();
            for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                context.put(entry.getKey(), entry.getValue());
            }
            
            // 处理并保存文档
            try (OutputStream outputStream = new FileOutputStream(new File(outputPath))) {
                report.process(context, outputStream);
            }
        }
    }
    
    /**
     * 使用POI直接替换Word文档中的变量标记（[变量名]格式）
     * 
     * @param templatePath Word模板文件路径
     * @param outputPath 输出文件路径
     * @param dataMap 变量数据Map
     * @throws Exception 处理异常
     */
    public static void processTemplateWithPOI(String templatePath, String outputPath, Map<String, Object> dataMap) throws Exception {
        XWPFDocument doc = new XWPFDocument(new FileInputStream(templatePath));
        
        // 替换段落中的变量
        for (XWPFParagraph paragraph : doc.getParagraphs()) {
            replaceParagraphVariables(paragraph, dataMap);
        }
        
        // 替换表格中的变量
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replaceParagraphVariables(paragraph, dataMap);
                    }
                }
            }
        }
        
        // 保存文档
        try (FileOutputStream out = new FileOutputStream(outputPath)) {
            doc.write(out);
        }
        doc.close();
    }
    
    /**
     * 替换段落中的变量
     * 
     * @param paragraph 段落
     * @param dataMap 变量数据Map
     */
    private static void replaceParagraphVariables(XWPFParagraph paragraph, Map<String, Object> dataMap) {
        String text = paragraph.getText();
        if (text != null && text.contains("[") && text.contains("]")) {
            List<Integer> runIndexList = new ArrayList<>();
            List<XWPFRun> runs = paragraph.getRuns();
            
            // 找出包含变量的runs
            for (int i = 0; i < runs.size(); i++) {
                String runText = runs.get(i).getText(0);
                if (runText != null && (runText.contains("[") || runText.contains("]"))) {
                    runIndexList.add(i);
                }
            }
            
            // 重新拼接text
            if (runIndexList.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < runs.size(); i++) {
                    XWPFRun run = runs.get(i);
                    if (run != null && run.getText(0) != null) {
                        sb.append(run.getText(0));
                    }
                }
                
                String completeText = sb.toString();
                
                // 查找并替换变量
                Pattern pattern = Pattern.compile("\\[(.*?)\\]");
                Matcher matcher = pattern.matcher(completeText);
                
                while (matcher.find()) {
                    String varName = matcher.group(1);
                    String varValue = dataMap.containsKey(varName) ? String.valueOf(dataMap.get(varName)) : "";
                    completeText = completeText.replace("[" + varName + "]", varValue);
                }
                
                // 清除原有内容
                for (int index : runIndexList) {
                    if (index < runs.size()) {
                        runs.get(index).setText("", 0);
                    }
                }
                
                // 设置新内容
                if (runIndexList.size() > 0) {
                    XWPFRun firstRun = runs.get(runIndexList.get(0));
                    firstRun.setText(completeText, 0);
                }
            }
        }
    }
    
    /**
     * 提取Word文档中的变量列表（[变量名]格式）
     * 
     * @param docx Word文档字节数组
     * @return 变量列表
     * @throws IOException IO异常
     */
    public static List<String> extractVariables(byte[] docx) throws IOException {
        List<String> variables = new ArrayList<>();
        Pattern pattern = Pattern.compile("\\[(.*?)\\]");
        
        try (ByteArrayInputStream bis = new ByteArrayInputStream(docx);
             XWPFDocument doc = new XWPFDocument(bis)) {
            
            // 从段落中提取变量
            for (XWPFParagraph paragraph : doc.getParagraphs()) {
                String text = paragraph.getText();
                Matcher matcher = pattern.matcher(text);
                while (matcher.find()) {
                    String varName = matcher.group(1);
                    if (!variables.contains(varName)) {
                        variables.add(varName);
                    }
                }
            }
            
            // 从表格中提取变量
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
                            String text = paragraph.getText();
                            Matcher matcher = pattern.matcher(text);
                            while (matcher.find()) {
                                String varName = matcher.group(1);
                                if (!variables.contains(varName)) {
                                    variables.add(varName);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        return variables;
    }
    
    /**
     * 将Word文档转换为PDF
     * 
     * @param docxPath Word文档路径
     * @param pdfPath PDF输出路径
     * @throws Exception 转换异常 
     */
    public static void convertDocxToPdf(String docxPath, String pdfPath) throws Exception {
        // 加载Word文档
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(docxPath));
        
        // 设置字体映射
        Mapper fontMapper = new IdentityPlusMapper();
        // 添加中文字体支持
        fontMapper.getFontMappings().put("SimSun", PhysicalFonts.getPhysicalFonts().get("SimSun"));
        fontMapper.getFontMappings().put("宋体", PhysicalFonts.getPhysicalFonts().get("SimSun"));
        fontMapper.getFontMappings().put("Calibri", PhysicalFonts.getPhysicalFonts().get("SimSun"));
        fontMapper.getFontMappings().put("Arial", PhysicalFonts.getPhysicalFonts().get("SimSun"));
        wordMLPackage.setFontMapper(fontMapper);
        
        // 转换为PDF
        Docx4J.toPDF(wordMLPackage, new FileOutputStream(pdfPath));
    }
    
    /**
     * 将HTML内容转换为Word文档
     * 
     * @param html HTML内容
     * @param docxPath Word文档输出路径
     * @throws Exception 转换异常
     */
    public static void convertHtmlToDocx(String html, String docxPath) throws Exception {
        // 创建Word文档
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        // 获取主文档部分
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
        
        // 将HTML内容转换为DOCX格式并添加到文档中
        documentPart.addAltChunk(org.docx4j.openpackaging.parts.WordprocessingML.AltChunkType.Html, html.getBytes("UTF-8"));
        
        // 保存文档
        wordMLPackage.save(new File(docxPath));
    }
    
    /**
     * 测试方法
     */
    public static void main(String[] args) throws Exception {
        // 测试变量替换
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("productName", "主要汽管道");
        dataMap.put("productCode", "XY3-01");
        dataMap.put("specification", "Φ325×28");
        dataMap.put("drawingNo", "XY-MS-28");
        dataMap.put("material", "12Cr1MoVG");
        dataMap.put("weldingNo", "h34/h55");
        dataMap.put("reportNo", "XY3MS-UT-202404-01");
        
        String templatePath = "D:/temp/template.docx";
        String outputPath = "D:/temp/output.docx";
        String pdfPath = "D:/temp/output.pdf";
        
        processTemplateWithPOI(templatePath, outputPath, dataMap);
        convertDocxToPdf(outputPath, pdfPath);
        
        System.out.println("处理完成！");
    }
}